package com.frank.loadinglibrary.cool;

import com.frank.loadinglibrary.utils.DensityUtil;
import com.frank.loadinglibrary.utils.SimpleAnimatorListener;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

public class SandClockComponent extends Component {

    Paint mPaint = new Paint();

    private String mGlassColor = "#8971fe";

    private String mSandColor = "#de13e3";

    private String mBackgroundColor = "#ffffff";

    private float mCapHeight = 5;

    private float mGlassThick = 10;

    private AnimatorValue sandAnimatorValue = new AnimatorValue();

    private float sandFraction = 0f;

    private boolean isUpright = true;

    public SandClockComponent setGlassColor(String glassColor) {
        this.mGlassColor = glassColor;
        return this;
    }

    public SandClockComponent setBackgroundColor(String backgroundColor) {
        this.mBackgroundColor = backgroundColor;
        return this;
    }

    public SandClockComponent setSandColor(String sandColor) {
        this.mSandColor = sandColor;
        return this;
    }

    public SandClockComponent setGlassThick(float glassThick) {
        this.mGlassThick = glassThick;
        return this;
    }

    public SandClockComponent setCapHeight(float capHeight) {
        this.mCapHeight = capHeight;
        return this;
    }

    public SandClockComponent(Context context) {
        this(context, null);
    }

    public SandClockComponent(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public SandClockComponent(Context context, AttrSet attrs, String styleName) {
        super(context, attrs, styleName);
        intiUI();
    }

    private void intiUI() {
        setupPaint();

        sandAnimatorValue.setDuration(5000);
        sandAnimatorValue.setLoopedCount(0);
        sandAnimatorValue.setValueUpdateListener((animatorValue, v) -> {
            sandFraction = v;
            invalidate();
        });

        sandAnimatorValue.setStateChangedListener(new SimpleAnimatorListener() {
            @Override
            public void onEnd(Animator animator) {
                super.onEnd(animator);
                float degree;
                if (isUpright) {
                    degree = 180;
                } else {
                    degree = 0;
                }
                AnimatorProperty animatorProperty = createAnimatorProperty();
                animatorProperty.setStateChangedListener(new SimpleAnimatorListener() {
                    @Override
                    public void onEnd(Animator animator) {
                        super.onEnd(animator);
                        isUpright = !isUpright;
                        sandAnimatorValue.start();
                    }
                });
                animatorProperty
                        .rotate(degree)
                        .setDuration(1000)
                        .start();

            }
        });

        sandAnimatorValue.start();

        DrawTask drawTask = (component, canvas) -> {
            drawBackground(canvas);

            int layerId = canvas.saveLayer(new RectFloat(0, 0, getWidth(), getHeight()), mPaint);
            drawGlass(canvas, true);

            mPaint.setBlendMode(BlendMode.SRC_IN);

            drawSand(canvas);

            mPaint.setBlendMode(null);

            canvas.restoreToCount(layerId);

            drawGlass(canvas, false);

        };

        addDrawTask(drawTask);
    }

    private void drawBackground(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setColor(new Color(Color.getIntColor(mBackgroundColor)));
        canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
    }

    private void drawSand(Canvas canvas) {

        float sandTotalHeight = getHeight() / 2f - getCapHeight();
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setColor(new Color(Color.getIntColor(mSandColor)));
        if (isUpright) {
            RectFloat sandRect = new RectFloat(0, getCapHeight() + sandTotalHeight * sandFraction, getWidth(), getHeight() / 2f);
            canvas.drawRect(sandRect, mPaint);

            canvas.drawRect(0, getHeight() / 2f + (1 - sandFraction) * sandTotalHeight, getWidth(), getHeight(), mPaint);
        } else {
            RectFloat sandRect = new RectFloat(0, getCapHeight(), getWidth(), sandTotalHeight * sandFraction + getCapHeight());
            canvas.drawRect(sandRect, mPaint);

            canvas.drawRect(0, getHeight() / 2f, getWidth(), getHeight() - sandFraction * sandTotalHeight - getCapHeight(), mPaint);
        }
    }

    private float getCapHeight() {
        return DensityUtil.dip2px(getContext(), mCapHeight);
    }

    private void setupPaint() {
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setAntiAlias(true);
    }

    private void drawGlass(Canvas canvas, boolean isModule) {

        int width = getWidth();
        int height = getHeight();
        float curveHeight = height - 2 * mCapHeight;
        int capWidth = width / 2;
        float capHeight = DensityUtil.dip2px(getContext(), mCapHeight);
        float capLeft = (width - capWidth) / 2f;
        float capRight = capLeft + capWidth;
        float upperCapTop = 0;
        float upperCapBottom = capHeight;

        if (isModule) {
            mPaint.setColor(new Color(Color.getIntColor(mBackgroundColor)));
        } else {
            mPaint.setColor(new Color(Color.getIntColor(mGlassColor)));
            canvas.drawRoundRect(new RectFloat(capLeft, upperCapTop, capRight, upperCapBottom), capHeight / 2f, capHeight / 2f, mPaint);

            float lowerCapTop = height - capHeight;
            float lowerCapBottom = height;
            canvas.drawRoundRect(new RectFloat(capLeft, lowerCapTop, capRight, lowerCapBottom), capHeight / 2f, capHeight / 2f, mPaint);

            mPaint.setStyle(Paint.Style.STROKE_STYLE);
            mPaint.setStrokeWidth(mGlassThick);
        }


        float xOffset = capWidth / 5f;
        Path curvePath = new Path();
        Point leftTopPoint = new Point(capLeft + capWidth / 10f, upperCapBottom - mGlassThick);
        Point leftJoint = new Point(width / 2f - DensityUtil.dip2px(getContext(), 1.5f), height / 2f);
        Point upperLeftCenterPoint = new Point((leftTopPoint.getPointX() + leftJoint.getPointX()) / 2f - xOffset, (leftTopPoint.getPointY() + leftJoint.getPointY()) / 2f);
        Point lowerLeftCenterPoint = new Point((leftTopPoint.getPointX() + leftJoint.getPointX()) / 2f - xOffset, (leftTopPoint.getPointY() + leftJoint.getPointY()) / 2f + curveHeight / 2f);
        Point leftBottomPoint = new Point(leftTopPoint.getPointX(), height - capHeight + mGlassThick);
        curvePath.moveTo(leftTopPoint);
        curvePath.quadTo(upperLeftCenterPoint, leftJoint);
        curvePath.quadTo(lowerLeftCenterPoint, leftBottomPoint);


        Point rightTopPoint = new Point(capRight - capWidth / 10f, upperCapBottom - mGlassThick);
        Point rightJoint = new Point(width / 2f + DensityUtil.dip2px(getContext(), 1.5f), height / 2f);
        Point upperRightCenterPoint = new Point((rightTopPoint.getPointX() + rightJoint.getPointX()) / 2f + xOffset, (rightTopPoint.getPointY() + rightJoint.getPointY()) / 2f);
        Point lowerRightCenterPoint = new Point((rightTopPoint.getPointX() + rightJoint.getPointX()) / 2f + xOffset, (rightTopPoint.getPointY() + rightJoint.getPointY()) / 2f + curveHeight / 2f);
        Point rightBottomPoint = new Point(rightTopPoint.getPointX(), height - capHeight + mGlassThick);
        curvePath.lineTo(rightBottomPoint);
        curvePath.quadTo(lowerRightCenterPoint, rightJoint);
        curvePath.quadTo(upperRightCenterPoint, rightTopPoint);
        canvas.drawPath(curvePath, mPaint);

        if (isModule) {
            mPaint.setColor(new Color(Color.getIntColor(mSandColor)));
            if (isUpright) {
                canvas.drawRect(leftJoint.getPointX(), height / 2f, rightJoint.getPointX(), height - getCapHeight(), mPaint);
            } else {
                canvas.drawRect(leftJoint.getPointX(), capHeight, rightJoint.getPointX(), getHeight() / 2f, mPaint);

            }
        }
    }

}
